package com.small.sentinel.context;

import com.small.sentinel.Constants;
import com.small.sentinel.Context;
import com.small.sentinel.EntryType;
import com.small.sentinel.node.DefaultNode;
import com.small.sentinel.node.EntranceNode;
import com.small.sentinel.slotchain.StringResourceWrapper;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class ContextUtil {

    /**
     * 线程上下文
     */
    public static ThreadLocal<Context> contextHolder = new ThreadLocal<>();

    /**
     * 资源节点缓存
     */
    private static volatile Map<String, DefaultNode> contextNameNodeMap = new HashMap<>();

    private static final ReentrantLock LOCK = new ReentrantLock();

    private static final Context NULL_CONTEXT = new NullContext();

    static {
        // 初始化根节点
        initDefaultContext();
    }

    private static void initDefaultContext() {
        String defaultContextName = Constants.CONTEXT_DEFAULT_NAME;
        EntranceNode node = new EntranceNode(new StringResourceWrapper(defaultContextName, EntryType.IN), null);
        Constants.ROOT.addChild(node);
        contextNameNodeMap.put(defaultContextName, node);
    }

    public static Context enter(String name, String origin) {
        //资源名不能与默认根节点名相同
        if (Constants.CONTEXT_DEFAULT_NAME.equals(name)) {
            throw new RuntimeException(
                    "The " + Constants.CONTEXT_DEFAULT_NAME + " can't be permit to defined!");
        }
        return trueEnter(name, origin);
    }

    protected static Context trueEnter(String name, String origin) {
        Context context = contextHolder.get();
        if (context == null) {
            LOCK.lock();
            try {
                if (context == null) {
                    DefaultNode node = contextNameNodeMap.get(name);
                    if (node == null) {
                        //如果节点超过了最大数 就不进行校验
                        if (contextNameNodeMap.size() > Constants.MAX_CONTEXT_NAME_SIZE) {
                            contextHolder.set(NULL_CONTEXT);
                            return NULL_CONTEXT;
                        } else {
                            node = new EntranceNode(new StringResourceWrapper(name, EntryType.IN), null);
                            Map<String, DefaultNode> newMap = new HashMap(contextNameNodeMap.size() + 1);
                            newMap.putAll(contextNameNodeMap);
                            newMap.put(name, node);
                            contextNameNodeMap = newMap;
                            Constants.ROOT.addChild(node);
                        }

                    }
                    context = new Context(node, name);
                    context.setOrigin(origin);
                    contextHolder.set(context);
                }
            } finally {
                LOCK.unlock();
            }
        }
        return context;
    }


    /**
     * 清除线程上下文
     */
    public static void exit() {
        Context context = contextHolder.get();
        if (context != null && context.getCurEntry() == null) {
            contextHolder.set(null);
        }
    }

    /**
     * 获取线上下文
     *
     * @return
     */
    public static Context getContext() {
        return contextHolder.get();
    }


    /**
     * 默认的上下文
     * @param context
     * @return
     */
    public static boolean isDefaultContext(Context context) {
        if (context == null) {
            return false;
        }
        return Constants.CONTEXT_DEFAULT_NAME.equals(context.getName());
    }
}
